/**
 * @file:  	cn_game.cpp
 * @date:   2011/5/3
 * @session encoding: 	ISO 8859-2
 * @author: Zdeněk Coufal, xcoufa06@stud.fit.vutbr.cz
 * @author: Petr Bušina, xbusin01@stud.fit.vutbr.cz
 * @section PROJECT:
 *    Projekt ICP: Člověče, nezlob se!
 * @section DESCRIPTION:
 *          Modul obsahuje metody třídy TGame
 */



//C++
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstring>
#include <cstdlib>

#include "cn_game.h" // definice třídy TGame, struktury TPlayer a struktury SAccount

#include <QtXml/QDomComment>
#include <QFile>
#include <QTextStream>

using namespace std;

/**
 *	@function TGame::TGame
 *  @param char *pattern vzor hracího pole
 *  @param int size velikost hracího pole
 * 	@section Explicitní konstruktor třídy TGame
 */
TGame::TGame(char *pattern, int size)
{
  p_pattern = string(pattern, size + 16);
  p_size = size;
  p_actual = &p_players[0];
  loaded = false;
  on_draw = 0;
  on_draw_again = false;

  for (int i = 0; i < 4; i++)
  {
    p_players[i].id = i;
    p_players[i].free = true;
    p_players[i].ready = false;
    p_players[i].out = false;
  }
}

/**
 *	@function TGame::TGame
 * 	@section Explicitní konstruktor třídy TGame
 */
TGame::TGame()
{
  p_actual = &p_players[0];
  loaded = false;
  on_draw = 0;
  on_draw_again = false;

  for (int i = 0; i < 4; i++)
  {
    p_players[i].id = i;
    p_players[i].free = true;
    p_players[i].ready = false;
    p_players[i].out = false;
  }
}

/**
 *	@function TGame::~TGame
 * 	@section Destruktor třídy TGame
 */
TGame::~TGame()
{
}

/**
 *	@function TGame::set_player
 *  @param int id identifikátor hráče
 * 	@section Nastaví ukazatel aktuálního hráče
 */
void TGame::set_player(int id)
{
  p_actual = &p_players[id];
}

/**
 *	@function TGame::set_player_incredentials
 *  @param int id identifikátor hráče
 *  @param string login jméno hráče
 *  @param pswd string pswd heslo hráče
 *  @param int type typ hráče
 * 	@section Nastaví ukazatel aktuálního hráče
 */
void TGame::set_player_incredentials(int id, string login, string pswd, int type)
{
  set_player(id);
  p_actual->login = login;
  p_actual->password = pswd;
  p_actual->type = type;

#ifdef DEBUG
cerr << "Game: Nastavuji údaje hráče" << endl
     << "ID: " << id << endl
     << "login: " << login << endl
     << "heslo: " << pswd << endl
     << "typ: " << type << endl;
#endif

}

/**
 *	@function TGame::set_player_socket
 *  @param int id identifikátor hráče
 *  @param int socket komunikační soket
 * 	@section Nastaví soket pro komunikaci s aktuálním hráčem
 */
void TGame::set_player_socket(int id, int socket)
{
  set_player(id);
  p_actual->socket_id = socket;

#ifdef DEBUG
cerr << "Game: Nastavuji soket hráče" << endl
     << "ID: " << id << endl
     << "soket: " << socket << endl;
#endif
}

/**
 *	@function TGame::set_player_ready
 *  @param int id identifikátor hráče
 * 	@section Nastaví příznak, že je hráč připraven začít hru
 */
void TGame::set_player_ready(int id)
{
  set_player(id);
  p_actual->ready = true;

#ifdef DEBUG
cerr << "Game: Hráč připraven" << endl
     << "ID: " << id << endl;
#endif
}

/**
 *	@function TGame::set_player_out
 *  @param int id identifikátor hráče
 * 	@section Nastaví příznak, že hráč skončil hru
 */
void TGame::set_player_out(int id)
{
  set_player(id);
  p_actual->out = true;

  #ifdef DEBUG
  cerr << "Game: Hráč skončil" << endl
       << "ID: " << id << endl;
  #endif
}

/**
 *	@function TGame::set_player_fig
 *  @param int id identifikátor hráče
 *  @param int fig_id identifikátor figurky
 * 	@section nastaví pozici dané figurky daného hráče
 */
void TGame::set_player_fig(int id, int fig_id, int value)
{
  set_player(id);
  p_actual->fig[fig_id] = value;

  #ifdef DEBUG
  cerr << "Game: Nastavuji figurku hráče" << endl
       << "ID: " << id << endl
       << "fig ID: " << fig_id << endl
       << "hodnota: " << value << endl;
  #endif
}

/**
 *	@function TGame::get_player_fig
 *  @param int id identifikátor hráče
 *  @param int fig_id identifikátor figurky
 * 	@return vrací pozici dané figurky daného hráče
 */
int TGame::get_player_fig(int id, int fig_id)
{
  set_player(id);
  return p_actual->fig[fig_id];
}

/**
 *	@function TGame::get_player_socket
 *  @param int id identifikátor hráče
 * 	@section Nastaví příznak, že hráč skončil hru
 *  @return vrací soket hráče s identifikátorem id
 */
int TGame::get_player_socket(int id)
{
  set_player(id);
  return p_actual->socket_id;
}

/**
 *	@function TGame::get_player_type
 *  @param int id identifikátor hráče
 * 	@section Získá typ hráče
 *  @return vrací typ hráče s identifikátorem id
 */
int TGame::get_player_type(int id)
{
  set_player(id);
  return p_actual->type;
}

/**
 *	@function TGame::is_player_out
 *  @param int id identifikátor hráče
 * 	@section Získá příznak, zda je hráč ve hře
 *  @return Vrací true pokud je hráč ve hře nebo false, pokud již skončil
 */
bool TGame::is_player_out(int id)
{
  set_player(id);
  return p_actual->out;
}

/**
 *	@function TGame::get_player_login
 *  @param int id identifikátor hráče
 * 	@section Získá login hráče
 *  @return Vrací login hráče.
 */
string TGame::get_player_login(int id)
{
  set_player(id);
  return p_actual->login;
}

/**
 *	@function TGame::get_size
 *  @return Vrací velikost herního pole.
 */
int TGame::get_size()
{
  return p_size;
}

/**
 *	@function TGame::get_pattern
 *  @return Vrací vzor herního pole
 */
string TGame::get_pattern()
{
  return p_pattern;
}

/**
 *	@function TGame::set_game_plan
 *  @param char *pattern vzor hracího pole z funkce cnRandomPattern
 *  @param int size velikost hracího pole
 * 	@section nastaví herní pole
 */
void TGame::set_game_plan(char *pattern, int size)
{
  p_pattern = string(pattern, size + 16);
  p_size = size;
  for (int i = 0; i < (p_size + 16); i++) p_pattern[i] += 48;
}

/**
 *	@function TGame::players_ready
 *  @return vrací true, pokud jsou všichni hráči připravení jinak false
 */
bool TGame::all_ready()
{
  for (int i = 0; i < 4; i++)
  {
    if ((p_players[i].type == 1) && (!p_players[i].ready))
      return false;
  }

  return true;
}

/**
 *	@function TGame::get_free_id
 *  @return vrací volný identifikátor hráče nebo -1 jestliže už sou všechny obsazeny
 */
int TGame::get_free_id()
{
  for (int i = 0; i < 4; i++)
  {
    if ((p_players[i].type == 1) && (p_players[i].free))
    {
      set_id_nonfree(i);
      return i;
    }
  }

  return -1;
}

/**
 *	@function TGame::set_id_nonfree
 *  @param int id identifikátor hráče
 * 	@section Nastaví identifikátor hráče jako obsazen
 */
void TGame::set_id_nonfree(int id)
{
  set_player(id);
  p_actual->free = false;
}

/**
 *	@function TGame::game_full
 *  @return vrací true, pokud jsou již obsazeny všechny sloty, jinak false
 */
bool TGame::game_full()
{
  for (int i = 0; i < 4; i++)
  {
    if ((p_players[i].type == 1) && (p_players[i].free))
      return false;

      #ifdef DEBUG
      cerr << "Game: game_full" << endl
           << "ID: " << i << " : " << p_players[i].free << endl;
      #endif
  }

  return true;
}

/**
 *	@function TGame::game_loaded
 *  @return vrací true, pokud byla hra načtena nebo false, jde-li o novou hru
 */
bool TGame::game_loaded()
{
  return loaded;
}

/**
 *	@function TGame::get_my_id
 *  @param string login jméno hráče
 * 	@section Zjistí, zda patří hráč do instance načtené hry
 *  @return vrací ID hráče, kterému odpovídají autentizační údaje nebo -1, pokud do této hry nepatří
 */
int TGame::get_my_id(std::string login)
{
  for (int i = 0; i < 4; i++)
  {
    if (p_players[i].login == login)
    {
      set_id_nonfree(i);
      return i;
    }
  }

  return -1;
}

/**
 *	@function TGame::get_player_on_draw
 *  @return vrací ID hráče, který je aktuálně na tahu nebo -1 pokud všichni skončili
 */
int TGame::get_player_on_draw()
{
  while (1) /// TODO all_out ?
  {
    if (all_out())
      return -1;

    if (on_draw_again)
    {
      #ifdef DEBUG
      cerr << "Game: get_player_on_draw (AGAIN)" << endl
           << "ID: " << on_draw << endl;
      #endif
      on_draw_again = false;
      return on_draw;
    }
    else if (first_draw)
    {
      #ifdef DEBUG
      cerr << "Game: get_player_on_draw : první výběr" << endl;
      #endif
      first_draw = false;
    }
    else
      on_draw = (on_draw + 1) % 4;

    if ((get_player_type(on_draw) == 0) || is_player_out(on_draw))
      continue;
    else
      return on_draw;
  }
}

/**
 *	@function TGame::all_out
 *  @return vrací true pokud už všichni hráči skončili nebo false je-li ještě někdo ve hře
 */
bool TGame::all_out()
{
  for (int i = 0; i < 4; i++)
  {
    if ((p_players[i].type == 1) && (!p_players[i].out))
      return false;
  }

  return true;
}

/**
 *	@function TGame::set_again_flag
 *  @section nastaví příznak, že aktuální hráč, co provedl tah, zůstává na tahu i příští kolo, protože hodil šestku
 */
void TGame::set_again_flag()
{
  on_draw_again = true;
}

/**
 *	@function TGame::was_on_draw
 *  @return vrací ID posledně vylosovaného hráče na tahu
 */
int TGame::was_on_draw()
{
  return on_draw;
}

/**
 *	@function TGame::load_game
 *  @param TPacket* packet zpráva s informacemi o načtení hry
 * 	@section načte síťovou hru ze souboru
 *  @return vrací 0, pokud načtení proběhlo v pořádku jinak -1
 */
int TGame::load_game(TPacket *packet)
{
  //f = cnFileManager->getOpenFileName(this,"Chose file.","resources/saves");
  string f_pattern = "((.*/)?([^/.$]+)?(.?([A-Za-z0-9].*)?))";

  string p_file;
  string* matches = new string[6];

  int stat = 0;

  TPacket tmp(PEXCEPT);

  stat = tmp.parser (packet->get_str_par(2), matches, f_pattern.c_str(), 6);

  if (!stat)
  {
    p_file = matches[3] + matches[4];
    delete[] matches;
  }
  else
  {
    delete[] matches;
    return -1;
  }

  #ifdef DEBUG
  cerr << "Game: load_game" << endl
       << "file: " << p_file << endl;
  #endif

  QFile file(QString::fromStdString("save/" + p_file));

  if( !file.open(QIODevice::ReadOnly))
    return -1;

  QDomDocument xload("LSaveCN");
  if(!xload.setContent(&file))
  {
    file.close();
    return -1;
  }
  file.close();

  QDomElement xbody = xload.documentElement();
  if(xbody.tagName() != "body")
    return -1;

  QDomNode node_iter = xbody.firstChild();

  QDomElement xplan = node_iter.toElement();
  node_iter = node_iter.nextSibling();

  QDomElement xplay = node_iter.toElement();
  node_iter = node_iter.nextSibling();

  QDomElement xname = node_iter.toElement();
  node_iter = node_iter.nextSibling();

  QDomElement xfig = node_iter.toElement();

  if(!xplan.isNull() && !xplay.isNull() && !xfig.isNull())
  {
    if((xplan.tagName() == "plan") && (xplay.tagName() == "players") && (xname.tagName() == "names") && (xfig.tagName() == "figurines"))
    {
      p_size = xplan.attribute("size").toInt();
      on_draw = xplan.attribute("turn").toInt();

      if (xplan.attribute("on_draw_again").toInt() == 0)
        on_draw_again = false;
      else
        on_draw_again = true;

      p_pattern = xplan.attribute("pattern").toStdString();

      for (int i = 0; i < 4; i ++)
        set_player_incredentials(i, xname.attribute("slot" + QString::number(i),"").toStdString(),"", xplay.attribute("slot" + QString::number(i),"").toInt());

      set_player_fig(0, 0, xfig.attribute("fig0", "").toInt());
      set_player_fig(0, 1, xfig.attribute("fig1", "").toInt());
      set_player_fig(0, 2, xfig.attribute("fig2", "").toInt());
      set_player_fig(0, 3, xfig.attribute("fig3", "").toInt());
      set_player_fig(1, 0, xfig.attribute("fig4", "").toInt());
      set_player_fig(1, 1, xfig.attribute("fig5", "").toInt());
      set_player_fig(1, 2, xfig.attribute("fig6", "").toInt());
      set_player_fig(1, 3, xfig.attribute("fig7", "").toInt());
      set_player_fig(2, 0, xfig.attribute("fig8", "").toInt());
      set_player_fig(2, 1, xfig.attribute("fig9", "").toInt());
      set_player_fig(2, 2, xfig.attribute("fig10", "").toInt());
      set_player_fig(2, 3, xfig.attribute("fig11", "").toInt());
      set_player_fig(3, 0, xfig.attribute("fig12", "").toInt());
      set_player_fig(3, 1, xfig.attribute("fig13", "").toInt());
      set_player_fig(3, 2, xfig.attribute("fig14", "").toInt());
      set_player_fig(3, 3, xfig.attribute("fig15", "").toInt());

    #ifdef DEBUG
    cerr << "Game: load_game" << endl;

    for (int i = 0; i < 4; i++)
    {
      cerr << "ID: " << i << endl;
      cerr << "fig0:"<< get_player_fig(i, 0) << endl;
      cerr << "fig1:"<< get_player_fig(i, 1) << endl;
      cerr << "fig2:"<< get_player_fig(i, 2) << endl;
      cerr << "fig3:"<< get_player_fig(i, 3) << endl;
    }
    #endif
    }
  }

  loaded = true;
  return 0;
}

/**
 *	@function TGame::save_game
 *  @param TPacket* packet zpráva s informacemi o uložení hry
 * 	@section uloží aktuální síťovou hru
 *  @return vrací 0, pokud uložení proběhlo v pořádku jinak -1
 */
int TGame::save_game(TPacket *packet)
{
  QDomDocument xsav("LSave");
  QDomElement xbody = xsav.createElement("body");

  xsav.appendChild(xbody);

  //cnGamePlan->getCurrentState(&gsize,&gpattern[0],&gplayers[0],&gnames[0],&gfigu[0],&gturn);
  //for (i = 0; i < (gsize + 16); i++) gpattern[i] += 48;

  QDomElement xplan = xsav.createElement("plan");
  xplan.setAttribute("size",p_size);
  xplan.setAttribute("turn",on_draw);
  xplan.setAttribute("pattern",QString::fromStdString(p_pattern));
  xplan.setAttribute("on_draw_again",int(on_draw_again));

  xbody.appendChild(xplan);

  QDomElement xplay = xsav.createElement("players");
  xplay.setAttribute("slot0",get_player_type(0));
  xplay.setAttribute("slot1",get_player_type(1));
  xplay.setAttribute("slot2",get_player_type(2));
  xplay.setAttribute("slot3",get_player_type(3));

  xbody.appendChild(xplay);

  QDomElement xname = xsav.createElement("names");
  xname.setAttribute("slot0",QString::fromStdString(get_player_login(0)));
  xname.setAttribute("slot1",QString::fromStdString(get_player_login(1)));
  xname.setAttribute("slot2",QString::fromStdString(get_player_login(2)));
  xname.setAttribute("slot3",QString::fromStdString(get_player_login(3)));

  xbody.appendChild(xname);

  QDomElement xfig = xsav.createElement("figurines");

  for (int i = 0; i < 16; i++)
    xfig.setAttribute("fig"+QString::number(i),packet->get_num_par(i));

  xbody.appendChild(xfig);

  //QString f = cnFileManager->getSaveFileName(this,"Chose file name.","saves");

  string f_pattern = "((.*/)?([^/.$]+)?(.?([A-Za-z0-9].*)?))";

  string p_file;
  string* matches = new string[6];

  int stat = 0;

  TPacket tmp(PEXCEPT);

  stat = tmp.parser (packet->get_str_par(0), matches, f_pattern.c_str(), 6);

  if (!stat)
  {
    p_file = matches[3] + matches[4];
    delete[] matches;
  }
  else
  {
    delete[] matches;
    return -1;
  }

  #ifdef DEBUG
  cerr << "Game: save_game" << endl
       << "file: " << p_file << endl;
  #endif

  QFile file("save/" + QString::fromStdString(p_file));
  if(!file.open(QIODevice::WriteOnly))
  {
     //QMessageBox msg;
     //msg.setText("Nelze ulozit soubor");
     //msg.show();
     return -1;
  }

  QTextStream ts(&file);
  ts << xsav.toString();
  file.close();

  return 0;
}

/**
 *	@function TGame::check_account
 *  @param string login jméno hráče
 *  @param login heslo hráče
 * 	@section Zjistí, zda má hráč účet na serveru.
 *  @return vrací true, pokud se hráč autentizoval, jinak false
 */
bool TGame::check_account(string login, string pswd)
{
  for(std::vector<SAccount>::iterator i = p_accounts.begin(); i != p_accounts.end(); i++)
  {
    if (i->login == login && i->password == pswd)
      return true;
  }
  return false;
}

/**
 *	@function TGame::get_accounts
 *  @param const char *filename jméno autentizačního souboru
 * 	@section Načte databázi jmen a příslušných hesel do vektoru účtů třídy
 *  @return vrací 0, pokud vše proběhlo v pořádku jinak -1
 */
int TGame::get_accounts(const char * filename)
{
  ifstream file(filename, ifstream::in);
  string line;

  if (file.is_open())
  {
    stringstream iss;

    while ( getline(file, line) )
    {
      iss << line;

      string token;
      SAccount new_account;
      int order = 0;

      while ( getline(iss, token, ',') )
      {
        if (order == 0)
        {
          new_account.login = token;
          order++;
        }
        else
        {
          new_account.password = token;
          p_accounts.push_back(new_account);
          break;  // stačí dvě hodnoty
        }
      }

      iss.clear();
    }

    file.close();

    #ifdef DEBUG
    cerr << "Game: Načtená databáze hesel" << endl;
    #endif

    for(std::vector<SAccount>::iterator i = p_accounts.begin(); i != p_accounts.end(); i++)
    {
      cerr << i->login << ":" << i->password << endl;
      cerr << i->login.length() << " : " << i->password.length() << endl;
    }

    return 0;
  }
  else
  {
    return -1;
  }
}

